<?php
namespace Teemo\MVC;

use Teemo\Db\Mysql;

use Teemo\Pool\Mysql as MysqlPool;

use Teemo\Coroutine\Coroutine;

use Teemo\Core\Config;

use Teemo\Core\Log;

class Dao
{
    /**
     * @var entity名
     */
    private $entity;

    /**
     * @var mysql连接数组
     * @desc 不同协程不能复用mysql连接，所以通过协程id进行资源隔离
     */
    private $dbs;

    /**
     * @var Mysql
     */
    private $db;

    //表名
    private $table;

    //主键字段名
    private $pkId;

    /**
     * @var 数据库配置名称, 用于处理多个数据库
     */
    private $dbTag;

    public function __construct($entity, $dbTag = null)
    {
        $this->entity = $entity;
        $entityRef    = new \ReflectionClass($this->entity);
        $this->table  = $entityRef->getConstant('TABLE_NAME');
        $this->pkId   = $entityRef->getConstant('PK_ID');
        $this->dbTag  = $dbTag;
    }

    /**
     * @param $dbTag
     *
     * @desc 更换数据库连接池
     */
    public function setDbName($dbTag)
    {
        $this->dbTag = $dbTag;
    }

    /**
     * @return Mysql
     * @throws \Exception
     */
    public function getDb()
    {
        $coId = Coroutine::getId();
        if (empty($this->dbs[$coId])) {
            //不同协程不能复用mysql连接，所以通过协程id进行资源隔离
            //达到同一协程只用一个mysql连接，不同协程用不同的mysql连接
            if ($this->dbTag) {
                $mysqlConfig = Config::get($this->dbTag);
            } else {
                $mysqlConfig = null;
            }
            $this->dbs[$coId] = MysqlPool::getInstance($mysqlConfig)->get();
            defer(function () {
                //利用协程的defer特性，自动回收资源
                $this->recycle();
            });
        }
        return $this->dbs[$coId];
    }

    /**
     * @throws \Exception
     * @desc mysql资源回收到连接池
     */
    public function recycle()
    {
        $coId = Coroutine::getId();
        if (!empty($this->dbs[$coId])) {
            $mysql = $this->dbs[$coId];
            MysqlPool::getInstance($mysql->getConfig())->put($mysql);
            unset($this->dbs[$coId]);
        }
    }

    /**
     * @return mixed
     * @desc 获取表名
     */
    public function getLibName()
    {
        return $this->table;
    }

    /**
     * @param int    $id
     * @param string $fields
     *
     * @return mixed
     * @desc 通过主键查询记录
     */
    public function fetchByPk($pk, $fields = '*')
    {
        return $this->fetchEntity("{$this->pkId}={$pk}", $fields);
    }


    /**
     * @param string $where
     * @param string $fields
     * @param null   $orderBy
     *
     * @return mixed
     * @desc 通过条件查询一条记录，并返回一个entity
     */
    public function fetchEntity($where = '1', $fields = '*', $orderBy = null)
    {
        $result = $this->fetchArray($where, $fields, $orderBy, 1);
        if (!empty($result[0])) {
            return new $this->entity($result[0]);
        }
        return null;
    }

    /**
     * @param string $where
     * @param string $fields
     * @param null   $orderBy
     * @param int    $limit
     *
     * @return mixed
     * @desc 通过条件查询记录列表，并返回entity列表
     */
    public function fetchAll($where = '1', $fields = '*', $orderBy = null, $limit = 0)
    {
        $result = $this->fetchArray($where, $fields, $orderBy, $limit);
        if (!empty($result)) {
            foreach ($result as $key => $value) {
                $result[$key] = new $this->entity($value);
            }
        }
        return $result;
    }


    /**
     * @param string $where
     * @param string $fields
     * @param null   $orderBy
     * @param int    $limit
     *
     * @return mixed
     * @desc 通过条件查询
     */
    public function fetchArray($where = '1', $fields = '*', $orderBy = null, $limit = 0)
    {
        $query = "SELECT {$fields} FROM {$this->getLibName()} WHERE {$where}";

        if ($orderBy) {
            $query .= " order by {$orderBy}";
        }

        if ($limit) {
            $query .= " limit {$limit}";
        }

        Log::alert($query);
        return $this->getDb()->query($query);
    }

    /**
     * @param array $array
     *
     * @return bool
     * @desc 插入一条记录
     */
    public function add(array $array)
    {
        $strFields = '`' . implode('`,`', array_keys($array)) . '`';
        $strValues = "'" . implode("','", array_values($array)) . "'";
        $query     = "INSERT INTO {$this->getLibName()} ({$strFields}) VALUES ({$strValues})";
        if (!empty($onDuplicate)) {
            $query .= 'ON DUPLICATE KEY UPDATE ' . $onDuplicate;
        }
        echo $query . PHP_EOL;
        $result = $this->getDb()->query($query);
        if (!empty($result['insert_id'])) {
            return $result['insert_id'];
        }
        return false;
    }

    /**
     * @param array $array
     * @param       $where
     *
     * @return bool
     * @throws \Exception
     * @desc 按条件更新记录
     */
    public function update(array $array, $where)
    {
        if (empty($array)) {
            throw new \Exception('UPDATE EMPTY');
        }

        if (empty($where)) {
            throw new \Exception("UPDATE:Where can't be empty");
        }

        $strUpdateFields = '';
        foreach ($array as $key => $value) {
            $strUpdateFields .= "`{$key}`='{$value}',";
        }
        $strUpdateFields = rtrim($strUpdateFields, ',');
        $query           = "UPDATE {$this->getLibName()} SET {$strUpdateFields} WHERE {$where}";
        $request         = $this->getDb()->query($query);
        echo $query;
        return $request['affected_rows'];
    }

    /**
     * @param $where
     *
     * @return mixed
     * @throws \Exception
     * @desc 按条件删除记录
     */
    public function delete($where)
    {
        if (empty($where)) {
            throw new \Exception("UPDATE:Where can't be empty");
        }

        $query  = "DELETE FROM {$this->getLibName()} WHERE {$where}";
        $result = $this->getDb()->query($query);
        return $result['affected_rows'];
    }
}